home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 February: Tool Chest / Dev.CD Feb 94.toast / Tool Chest / Development Platforms / AppsToGo / AppsToGo.src / DTS.Lib / Print.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-18  |  10.4 KB  |  381 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** Program:     DTS.Lib
  5. ** File:        print.c
  6. ** Written by:  Eric Soldan
  7. ** Based on:    Code from Pete "Luke" Alexander.
  8. **
  9. ** Copyright © 1989-1991 Apple Computer, Inc.
  10. ** All rights reserved.
  11. */
  12.  
  13. /* You may incorporate this sample code into your applications without
  14. ** restriction, though the sample code has been provided "AS IS" and the
  15. ** responsibility for its operation is 100% yours.  However, what you are
  16. ** not permitted to do is to redistribute the source as "DSC Sample Code"
  17. ** after having made changes. If you're going to re-distribute the source,
  18. ** we require that you make it clear in the source that the code was
  19. ** descended from Apple Sample Code, but that you've made changes. */
  20.  
  21.  
  22.  
  23. /*****************************************************************************/
  24.  
  25.  
  26.  
  27. #include "DTS.Lib2.h"
  28. #include "DTS.Lib.protos.h"
  29.  
  30. #ifndef __ERRORS__
  31. #include <Errors.h>
  32. #endif
  33.  
  34. #ifndef __RESOURCES__
  35. #include <Resources.h>
  36. #endif
  37.  
  38. #ifndef __STRINGUTILS__
  39. #include "StringUtils.h"
  40. #endif
  41.  
  42.  
  43.  
  44. /*****************************************************************************/
  45.  
  46.  
  47.  
  48. static pascal void    PrintIdleProc(void);
  49. short                gPrintPage;
  50. static DialogPtr    gPrintingStatusDialog;
  51.  
  52.  
  53.  
  54. /*****************************************************************************/
  55.  
  56.  
  57.  
  58. /* This print-loop function is designed to be called under various situations.
  59. ** The big issue that it handles is finder printing.  If multiple documents
  60. ** are to be printed from the finder, the user should only see one job dialog
  61. ** for all the files.  (If a job dialog is shown for each file, how does the
  62. ** user know for which file the dialog is for?)  So, for situations where
  63. ** there is more than one file to be printed, call this code the first time
  64. ** with the firstJob boolean true.  Normally, the jobDlg boolean will also
  65. ** be true, except that under 7.0, you may be printing in the background.
  66. ** If this is the case, you don't want a job dialog for even the first file,
  67. ** and you should pass in false for the jobDlg boolean in this case.  For
  68. ** files 2-N, you should pass false for both booleans.  For regular application
  69. ** printing, you should pass true for both booleans, since the file is the
  70. ** first (only) file, and you are not in the background.
  71. **
  72. ** After calling this function to print a document, you need to call it
  73. ** again with a nil document handle.  The print record for the first (or only)
  74. ** document printed is preserved in a static variable.  This is so that the
  75. ** job dialog information can be passed on to documents 2-N in the print job.
  76. ** Calling this function with the document handle nil tells this function
  77. ** that you are done printing documents, and that the print record for the
  78. ** first job can be disposed of. */
  79.  
  80. #pragma segment Print
  81. OSErr    PrintDocument(FileRecHndl frHndl, Boolean jobDlg, Boolean firstJob)
  82. {
  83.     OSErr            err;
  84.     THPrint            prRecHndl;
  85.     TPPrPort        printPort;
  86.     GrafPtr            oldPort;
  87.     short            i, keepResFile, copies, fstPage, lstPage;
  88.     TPrStatus        status;
  89.     ControlHandle    proceedButton;
  90.     Rect             rct;
  91.     Handle            txtHndl;
  92.     Str255            txt, txt2;
  93.  
  94.     static THPrint    prMergeHndl;
  95.  
  96.     if (!frHndl) {
  97.         if (prMergeHndl) {
  98.             DisposeHandle((Handle)prMergeHndl);
  99.             prMergeHndl = nil;
  100.         }
  101.         return(noErr);
  102.     }
  103.  
  104.     gPrintingStatusDialog = nil;
  105.  
  106.     if (!(prRecHndl = (THPrint)NewHandle(sizeof(TPrint)))) return(memFullErr);
  107.         /* If we can't generate a print record handle, we are out of here. */
  108.  
  109.     BlockMove((Ptr)&((*frHndl)->d.doc.fhInfo.print), (Ptr)(*prRecHndl), sizeof(TPrint));
  110.         /* Get the document's print info into the print record handle. */
  111.  
  112.     GetPort(&oldPort);
  113.  
  114.     DoSetCursor(&qd.arrow);
  115.  
  116.     keepResFile = CurResFile();
  117.     PrOpen();
  118.     err = PrError();
  119.  
  120.     if (!err) {
  121.         if (!(*frHndl)->d.doc.fhInfo.printRecValid) {
  122.             PrintDefault(prRecHndl);            /* The document print record was never 
  123.             err = PrError();                    ** initialized.  Now is is. */
  124.         }
  125.         if (!err) {
  126.             PrValidate(prRecHndl);        /* Do this just 'cause Apple says so. */
  127.             err = PrError();
  128.         }
  129.         if (!err) {
  130.             if (jobDlg) {                /* User gets to click some buttons. */
  131.                 UnhiliteWindows();
  132.                 if (!(PrJobDialog(prRecHndl)))
  133.                     err = userCanceledErr;
  134.                 else
  135.                     err = PrError();
  136.                 HiliteWindows();
  137.             }
  138.         }
  139.         if (!err) {
  140.             if (!firstJob) {
  141.                 fstPage = (*prMergeHndl)->prJob.iFstPage;
  142.                 lstPage = (*prMergeHndl)->prJob.iLstPage;
  143.                 PrJobMerge(prMergeHndl, prRecHndl);
  144.                 (*prMergeHndl)->prJob.iFstPage = (*prRecHndl)->prJob.iFstPage = fstPage;
  145.                 (*prMergeHndl)->prJob.iLstPage = (*prRecHndl)->prJob.iLstPage = lstPage;
  146.                 err = PrError();
  147.                     /* For documents other than the first, do the PrJobMerge thing.
  148.                     ** Unfortunately, PrJobMerge is kind of broken.  The first and last
  149.                     ** page fields have to be cached and put back.  The rest of PrJobMerge
  150.                     ** seems to work okay. */
  151.             }
  152.         }
  153.  
  154.         if (!err) {            /* Put the defaulted/validated/jobDlg'ed print record in the doc. */
  155.             fstPage = (*prRecHndl)->prJob.iFstPage;
  156.             lstPage = (*prRecHndl)->prJob.iLstPage;
  157.             copies  = (*prRecHndl)->prJob.iCopies;
  158.             BlockMove((Ptr)(*prRecHndl), (Ptr)&((*frHndl)->d.doc.fhInfo.print), sizeof(TPrint));
  159.             (*frHndl)->d.doc.fhInfo.printRecValid = true;
  160.  
  161.             gPrintingStatusDialog = nil;
  162.             i = ((*prRecHndl)->prStl.wDev >> 8) & 0xFF;
  163.             if ((i == 1) || (i == 2))
  164.                 gPrintingStatusDialog = GetNewDialog(rPrStatusDlg, nil, (WindowPtr)-1);
  165.             if (gPrintingStatusDialog) {
  166.                     /* The ImageWriter driver uses ParamText, so we can’t.
  167.                     ** If we try to, then the printer name shows up, instead of
  168.                     ** the document name.  Due to this, we have to parse our
  169.                     ** own text.  We expect dialog item#4 to have a c/r in it.
  170.                     ** We use the c/r instead of ^0, due to the ImageWriter driver.
  171.                     ** We just replace the c/r with the name of the document. */
  172.                 GetDItem(gPrintingStatusDialog, 4, &i, (Handle *)&txtHndl, &rct);
  173.                 GetIText(txtHndl, txt);
  174.                 for (i = *txt; i; --i) {
  175.                     if (txt[i] == 13) {
  176.                         txt[i] = *txt - i;
  177.                         txt[0] = i - 1;
  178.                         break;
  179.                     }
  180.                 }        /* We now have two pascal strings -- one right after the other. */
  181.                 pcpy(txt2, txt);                                /* Copy the first string. */
  182.                 pcat(txt2, (*frHndl)->fileState.fss.name);        /* Append the document name. */
  183.                 pcat(txt2, txt + *txt + 1);                        /* Append the second string. */
  184.                 SetIText(txtHndl, txt2);
  185.                 GetDItem(gPrintingStatusDialog, 1, &i, (Handle *)&proceedButton, &rct);
  186.                 HiliteControl(proceedButton, 255);
  187.                     /* Setup the proceed/pause/cancel dialog with the document name. */
  188.                 (*prRecHndl)->prJob.pIdleProc = PrintIdleProc;
  189.                 UseResFile(keepResFile);        /* Hook in the proceed/pause/cancel dialog. */
  190.                 UnhiliteWindows();
  191.             }
  192.  
  193.             for (i = 1; (i <= copies) && (!err); ++i) {
  194.  
  195.                 printPort = PrOpenDoc(prRecHndl, nil, nil);
  196.                 if (!(err = PrError())) {
  197.  
  198.                     gPrintPage = 1;
  199.                     while (gPrintPage <= lstPage) {
  200.  
  201.                         PrOpenPage(printPort, nil);
  202.  
  203.                         if (!(err = PrError()))
  204.                             err = DoImageDocument(frHndl);
  205.                                 /* Do the print thing here. */
  206.  
  207.                         PrClosePage(printPort);
  208.  
  209.                         if (!gPrintPage) break;
  210.                         ++gPrintPage;
  211.                     }
  212.                     gPrintPage = 0;
  213.                     PrCloseDoc(printPort);
  214.                 }
  215.             }
  216.         }
  217.  
  218.         if (
  219.             (!err) &&
  220.             ((*prRecHndl)->prJob.bJDocLoop == bSpoolLoop) &&
  221.             (!(err = PrError()))
  222.         ) {
  223.             PrPicFile(prRecHndl, nil, nil, nil, &status);
  224.             err = PrError();
  225.         }
  226.     }
  227.  
  228.     if (firstJob)
  229.         prMergeHndl = prRecHndl;
  230.     else
  231.         DisposeHandle((Handle)prRecHndl);
  232.  
  233.     if (gPrintingStatusDialog)
  234.         DisposeDialog(gPrintingStatusDialog);
  235.  
  236.     PrClose();
  237.     UseResFile(keepResFile);
  238.  
  239.     SetPort(oldPort);
  240.     HiliteWindows();
  241.  
  242.     if (err == iIOAbortErr)
  243.         err = noErr;
  244.  
  245.     return(err);
  246. }
  247.  
  248.  
  249.  
  250. /*****************************************************************************/
  251.  
  252.  
  253.  
  254. /* DonePrinting makes sure that PrintDocument gets rid of the prMergeHndl
  255. ** print record that is used for multiple document printing.  Call this after
  256. ** or the last document is printed, or you get a memory leak. */
  257.  
  258. #pragma segment Print
  259. void    DonePrinting(void)
  260. {
  261.     PrintDocument(nil, false, false);
  262. }
  263.  
  264.  
  265.  
  266. /*****************************************************************************/
  267.  
  268.  
  269.  
  270. /* PrintIdleProc will handle events in the 'Printing Status Dialog' which
  271. ** gives the user the option to 'Proceed', 'Pause', or 'Cancel' the current
  272. ** printing job during print time.
  273. **
  274. ** The buttons:
  275. **        1: Proceed
  276. **        2: Pause
  277. **        3: Cancel
  278. */
  279.  
  280. #pragma segment Print
  281. pascal void    PrintIdleProc(void)
  282. {
  283.     Boolean                button, paused;
  284.     ControlHandle        pauseButton, proceedButton;
  285.     DialogPtr            aDialog;
  286.     EventRecord            anEvent;
  287.     GrafPtr                oldPort;
  288.     Rect                 rct;
  289.     short                item, itemType, keepResFile;
  290.  
  291.     GetPort(&oldPort);
  292.  
  293.     UseResFile(keepResFile = CurResFile());
  294.  
  295.     GetDItem(gPrintingStatusDialog, 1, &itemType, (Handle *)&proceedButton, &rct);
  296.     HiliteControl(proceedButton, 255);
  297.     GetDItem(gPrintingStatusDialog, 2, &itemType, (Handle *)&pauseButton, &rct);
  298.  
  299.     paused = false;
  300.     do {
  301.         if (GetNextEvent((mDownMask + mUpMask + updateMask), &anEvent)) {
  302.             if (gPrintingStatusDialog != FrontWindow())
  303.                 SelectWindow(gPrintingStatusDialog);
  304.  
  305.             if (IsDialogEvent(&anEvent)) {
  306.                 button = DialogSelect(&anEvent, &aDialog, &item);
  307.  
  308.                 if ((button) && (aDialog == gPrintingStatusDialog)) {
  309.                     switch (item) {
  310.                         case 1:
  311.                             HiliteControl(pauseButton, 0);        /* Enable PAUSE    */
  312.                             HiliteControl(proceedButton, 255);    /* Disable PROCEED */
  313.                             paused = false;
  314.                             break;
  315.                         case 2:
  316.                             HiliteControl(pauseButton, 255);    /* Disable PAUSE  */
  317.                             HiliteControl(proceedButton, 0);    /* Enable PROCEED */
  318.                             paused = true;
  319.                             break;
  320.                         case 3:
  321.                             PrSetError(iPrAbort);               /* CANCEL printing */
  322.                             paused = false;
  323.                             break;
  324.                     }
  325.                 }
  326.             }
  327.         }
  328.     } while (paused != false); 
  329.  
  330.     SetPort(oldPort);
  331. }
  332.  
  333.  
  334.  
  335. /*****************************************************************************/
  336.  
  337.  
  338.  
  339. #pragma segment Print
  340. OSErr    PresentStyleDialog(FileRecHndl frHndl)
  341. {
  342.     OSErr        err;
  343.     THPrint        prRecHndl;
  344.     short        oldRes;
  345.  
  346.     if (!(prRecHndl = (THPrint)NewHandle(sizeof(TPrint)))) return(memFullErr);
  347.  
  348.     oldRes = CurResFile();
  349.     PrOpen();
  350.  
  351.     if (!(err = PrError())) {
  352.  
  353.         BlockMove((Ptr)&(*frHndl)->d.doc.fhInfo.print, (Ptr)*prRecHndl, sizeof(TPrint));
  354.             /* Get data, valid or not. */
  355.  
  356.         if (!(*frHndl)->d.doc.fhInfo.printRecValid)
  357.             PrintDefault(prRecHndl);
  358.         else
  359.             PrValidate(prRecHndl);
  360.  
  361.         if (!(err = PrError())) {
  362.             UnhiliteWindows();
  363.             if (PrStlDialog(prRecHndl)) {
  364.                 BlockMove((Ptr)*prRecHndl, (Ptr)&(*frHndl)->d.doc.fhInfo.print, sizeof(TPrint));
  365.                 (*frHndl)->d.doc.fhInfo.printRecValid = true;
  366.             }
  367.             else err = userCanceledErr;
  368.             HiliteWindows();
  369.         }
  370.     }
  371.  
  372.     DisposeHandle((Handle)prRecHndl);
  373.     PrClose();
  374.     UseResFile(oldRes);
  375.  
  376.     return(err);
  377. }
  378.  
  379.  
  380.  
  381.